﻿using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Net;
using System.Net.Sockets;
using System.ComponentModel;
using System.Text;
using IniParser;
using IniParser.Model;
using SpectralCamera.Enum;

namespace SpectralCamera.Extend
{
    public class CameraParameters
    {
        public int Addr { get; set; }
        /// <summary>
        /// 帧书周期
        /// </summary>
        public int Frame { get; set; }
        /// <summary>
        /// 积分时间
        /// </summary>
        public int[] JifenTime { get; } = new int[3];
        /// <summary>
        /// 积分电容
        /// </summary>
        public int[] JifenDR { get; } = new int[3];
        /// <summary>
        /// 增益
        /// </summary>
        public int[] Gain { get; } = new int[3];
        /// <summary>
        /// 偏执
        /// </summary>
        public int[] Bias { get; } = new int[3];
        public int[] LightCalib { get; } = new int[3];
    }

    public class Camera : IDisposable
    {
        private const string ConfigFile = "camera.conf";
        private const int CmdCurve = 0x0001;
        // 其他命令常量...

        public CameraParameters _params = new CameraParameters();
        private MyUdp _udp;
        private byte _cmdSerialNo;
        private BackgroundWorker _worker;

        public event Action<byte[]> CurveDataReceived;

        public Camera()
        {
            LoadSettings();
            InitializeWorker();
        }

        private void InitializeWorker()
        {
            _worker = new BackgroundWorker();
            _worker.DoWork += (s, e) => OnInit();
            _worker.RunWorkerAsync();
        }

        private void LoadSettings()
        {
            var parser = new FileIniDataParser();
            IniData data;
            if (File.Exists(ConfigFile))
            {
                data = parser.ReadFile(ConfigFile);
            }
            else
            {
                data = new IniData();
            }

            _params.Addr = int.Parse(data["Global"]["addr"] ?? "0");
            _params.Frame = int.Parse(data["Global"]["frame"] ?? "0");

            for (int i = 0; i < 3; i++)
            {
                _params.JifenTime[i] = int.Parse(data[$"JifenTime_{i}"]["value"] ?? "0");
                // 加载其他参数...
            }
        }

        public void SaveSettings()
        {
            var data = new IniData();
            data["Global"]["addr"] = _params.Addr.ToString();
            data["Global"]["frame"] = _params.Frame.ToString();

            for (int i = 0; i < 3; i++)
            {
                data[$"JifenTime_{i}"]["value"] = _params.JifenTime[i].ToString();
                // 保存其他参数...
            }

            var parser = new FileIniDataParser();
            parser.WriteFile(ConfigFile, data);
        }

        private void OnInit()
        {
            _udp = new MyUdp(6000, "192.168.0.4", 5000,false);
            _udp.RegisterRecvCallback(OnUdpMessageReceived);
            //_udp.OnReceived += OnUdpMessageReceived;
        }

        private void OnUdpMessageReceived(MessageUDP msg)
        {
            if (msg.Cmd == CmdCurve)
            {
                CurveDataReceived?.Invoke(msg.Data);
            }
        }

        public void SendStartCommand(bool start, int type)
        {
            var data = new byte[2] { (byte)(start ? 1 : 0), (byte)type };
            SendCommand(CmdCurve, data);
        }

        private void SendCommand(int cmd, byte[] data)
        {
            try
            {
                var packet = BuildNetworkPacket(cmd, _params.Addr, data);
                _udp.SendAsync(packet, packet.Length);
            }
            catch (Exception ex)
            {
                // 处理异常
            }
        }

        private byte[] BuildNetworkPacket(int cmd, int address, byte[] payload)
        {
            var packet = new byte[68];
            packet[0] = 0xA5;
            packet[1] = 0x5A;
            packet[3] = 0x02; // 模块类型
            packet[4] = (byte)address;//模块地址

            // 设置命令字段
            packet[6] = (byte)(cmd >> 8);
            packet[7] = (byte)cmd;
            packet[8] = _cmdSerialNo++;
            if (_cmdSerialNo > 255) _cmdSerialNo = 0;

            Buffer.BlockCopy(payload, 0, packet, 9, payload.Length);

            // 计算CRC
            var crcData = new byte[20];
            Buffer.BlockCopy(packet, 2, crcData, 0, 20);
            ushort crc = CalculateCrc(crcData);
            packet[22] = (byte)(crc >> 8);
            packet[23] = (byte)crc;

            // 包尾
            packet[24] = 0xFF;
            packet[25] = 0xFF;

            return packet;
        }

        private ushort CalculateCrc(byte[] data)
        {
            ushort crc = 0;
            foreach (byte b in data)
            {
                for (int j = 0x80; j != 0; j >>= 1)
                {
                    bool bitSet = (b & j) != 0;
                    bool crcHighBitSet = (crc & 0x8000) != 0;

                    crc <<= 1;
                    if (crcHighBitSet) crc ^= 0x1021;
                    if (bitSet) crc ^= 0x1021;
                }
            }
            return crc;
        }

        public void Dispose()
        {
            _udp?.Dispose();
            _worker?.Dispose();
        }
        public void OnSendParams(EnumAction enumAction)
        {
            SaveSettings(); // 对应原C++的save()
            int cmd = 0x0002;
            byte[] data = null;
            switch (enumAction)
            {
                case EnumAction.FramePeriod://0: // 帧频
                {
                        cmd = 0x0002;
                        data = new byte[4];
                        int frame = _params.Frame;
            
                        // 大端字节序转换
                        data[0] = (byte)((frame >> 24) & 0xFF);
                        data[1] = (byte)((frame >> 16) & 0xFF);
                        data[2] = (byte)((frame >> 8) & 0xFF);
                        data[3] = (byte)(frame & 0xFF);
            
                        //SendCommand(CMD_FRAME, data);
                        break;
                }
                case EnumAction.IntegrationTime: //1: // 积分时间
                {
                        cmd = 0x0003;

                        data = new byte[12];
                        // 三个通道的时间参数
                        for (int i = 0; i < 3; i++)
                        {
                            int offset = i * 4;
                            int time = _params.JifenTime[i];
                
                            data[offset]     = (byte)((time >> 24) & 0xFF);
                            data[offset + 1] = (byte)((time >> 16) & 0xFF);
                            data[offset + 2] = (byte)((time >> 8) & 0xFF);
                            data[offset + 3] = (byte)(time & 0xFF);
                        }
                        //SendCommand(CMD_JIFEN_TIME, data);
                        break;
                }
                case EnumAction.IntegralCapacitor: //2: // 积分电容
                {
                        cmd = 0x0004;

                        data = new byte[3];
            
                        // 直接取低8位
                        for (int i = 0; i < 3; i++)
                        {
                            data[i] = (byte)(_params.JifenDR[i] & 0xFF);
                        }
                        //SendCommand(CMD_JIFENDR, data);
                    break;
                }
                case EnumAction.Gain: //3: // 增益
                {
                        cmd = 0x0005;

                        data = new byte[3];
                        for (int i = 0; i < 3; i++)
                        {
                            data[i] = (byte)(_params.Gain[i] & 0xFF);
                        }
                        //SendCommand(CMD_GAIN, data);
                        break;
                }
                case EnumAction.Bigotry: //4: // 偏置
                {
                        cmd = 0x0006;

                        data = new byte[6];
                        for (int i = 0; i < 3; i++)
                        {
                            int bias = _params.Bias[i];
                            int position = i * 2;
                
                            // 符号位处理
                            data[position] = (byte)(bias > 0 ? 0 : 1);
                
                            // 绝对值处理
                            int absValue = Math.Abs(bias);
                            if (absValue > 255)
                                throw new ArgumentOutOfRangeException($"Bias值超出范围: {absValue}");
                
                            data[position + 1] = (byte)absValue;
                        }
                        //SendCommand(CMD_BIAS, data);
                        break;
                }
                case EnumAction.DarkCorrection: //获取黑校正
                {
                    cmd = 0x0007;

                    data = new byte[1] { 1};
                    //sendCmd(CMD_DARK_CALIB, m_params.addr, data, 3);
                    break;
                }
                case EnumAction.LightCorrection://获取明校正
                {
                    cmd = 0x0008;

                    data = new byte[3];
                    for (int i = 0; i < 3; i++)
                    {
                        data[i] = (byte)(_params.LightCalib[i] & 0xFF);
                    }
                    //SendCommand(CMD_LIGHT_CALIB, data);
                    break;
                }
                case EnumAction.SaveCorrection://获取明校正
                {

                    cmd = 0x0009;

                    data = new byte[1] { 1 };
                    //sendCmd(CMD_SAVE_CALIB, m_params.addr, data, 3);
                    break;
                }
            }
            if (data != null)
            {
                SendCommand(cmd, data);
            }
            
        }
        public void OnStart(EnumAction enumAction, bool  collectedStatus, EnumsignalType type)
        {
            SaveSettings(); // 对应原C++的save()
            int cmd = 0x0001;

            byte[] data = new byte[2];
            data[0] = (byte)(collectedStatus ? 1 : 0);
            data[1] = (byte)type;

            SendCommand(cmd, data);
        }
    }

    // 补充之前转换的MyUdp和MessageUDP类
}
